"use strict"

window.onload = function () {
    let submit = document.getElementById('submitData');
    let clear = document.getElementById('clear');
    let canvas = document.getElementById('qrCanvas');
    let select = document.getElementById('select');
    let lookForBtn = document.getElementById('lookFor');//寻像
    let separatorBtn = document.getElementById('separator');//分隔
    let locationBtn = document.getElementById('location');//定位
    let adjustBtn = document.getElementById('adjust');//纠正
    let formatBtn = document.getElementById('format');//格式
    let versionMessageBtn = document.getElementById('versionMessage');//版本
    let lineBtn = document.getElementById('line');//走位线路
    let dataBtn = document.getElementById('data');//数据
    let coverBtn = document.getElementById('cover');//掩摸
    let resultBtn = document.getElementById('result');//掩摸

    let Brush = canvas.getContext('2d');
    Brush.window = 672;
    Brush.Height = 672;
    Brush.fillStyle = '#ddd';
    Brush.fillRect(0, 0, Brush.window, Brush.Height);
    const eC = 0;//纠错等级（0,1,2,3）
    let recvV, isDrawed_Dict = {
        "xunxiang": false, "fenge": false, "dingwei": false, "jiuzheng": false,
        "geshi": false, "banben": false, "luxian": false, "data": false, "yanmo": false, "shengcheng": false
    };
    let cacheDataArr = new Array();
    let isAlterShield = "000";

    /**生成最终
     * 
     */
    submit.onclick = function () {
        let str = "111";//文本框内容

        if (str == "") {
            alert('请输入数据！');
            return;
        }

        clearBrush();//清除
        isDrawed_Dict = new Array();

        let data;
        //输出（模式指示符+字符计数指示符+数据）二进制数据
        if (GetVersion(MixingMode(str, 0).length) <= 9) data = MixingMode(str, 0);
        else if (GetVersion(MixingMode(str, 1).length) <= 26) data = MixingMode(str, 1);
        else data = MixingMode(str, 2);

        let version = GetVersion(data.length);//获取版本
        const vDataLength = GetVersionDataLength(version - 1);//获取版本最大数据容量
        data += GetFinish(vDataLength, data.length);//添加终止符
        data += GetFill(vDataLength, data.length);//添加填充码
        data = DataError(data, version);//最终数据字符串

        console.log('版本：' + version);	//打印版本
        console.log(data);	//打印最终数据


        let resultArr = new Array();//存放最终数据的数组
        for (let i = 0; i < 17 + (version * 4); i++) {
            resultArr[i] = new Array();
        }

        resultArr = LookFor(version, resultArr);//添加寻像图形和分隔符数据
        resultArr = Location(version, resultArr);//添加定位图形数据
        resultArr = Adjust(version, resultArr);//添加矫正图形数据
        resultArr = Format(version, '011', resultArr);//添加格式信息图形数据（最终的格式信息还不确定）
        resultArr = VersionMessage(version, resultArr);//添加版本信息图形数据
        //将数据添加到数组内
        for (let z = resultArr.length - 1, n = 0, direction = 0; z > 0; z -= 2, direction++) {
            if (z == 6) z--;
            if ((direction % 2) == 0) {
                for (let i = resultArr.length - 1; i >= 0; i--) {
                    for (let j = 0; j < 2; j++) {
                        if (resultArr[i][z - j] == undefined) {
                            resultArr[i][z - j] = data[n];
                            n++;
                        }
                    }
                }
            } else {
                for (let i = 0; i < resultArr.length; i++) {
                    for (let j = 0; j < 2; j++) {
                        if (resultArr[i][z - j] == undefined) {
                            resultArr[i][z - j] = data[n];
                            n++;
                        }
                    }
                }
            }
        }
        //防止出现数据位数不足
        for (let i = 0; i < resultArr.length; i++) {
            for (let j = 0; j < resultArr[0].length; j++) {
                if (resultArr[i][j] == undefined) resultArr[i][j] = 0;
            }
        }
        resultArr = Shield(resultArr);//最终数据
        let size = (Brush.window) / (resultArr.length);
        Brush.clearRect(0, 0, Brush.window, Brush.Height);
        //画出最终二维码图形
        for (let i = 0; i < resultArr.length; i++) {
            for (let j = 0; j < resultArr[0].length; j++) {
                if (resultArr[i][j] % 2 == 1 || resultArr[i][j] % 2 == 3) {
                    Brush.fillStyle = '#000';
                } else {
                    Brush.fillStyle = '#fff';
                }
                Brush.fillRect(j * size, i * size, size + 0.5, size + 0.5);
            }
        }
    }
    //寻像
    lookForBtn.onclick = function () {
        clearBrush();//清除
        if (!versionAlter()) {
            isDrawed_Dict["xunxiang"] = !isDrawed_Dict["xunxiang"];
        } else isDrawed_Dict["xunxiang"] = true;

        AddFunction();
    }
    //分割
    separatorBtn.onclick = function () {
        clearBrush();//清除
        if (!versionAlter()) {
            isDrawed_Dict["fenge"] = !isDrawed_Dict["fenge"];
        } else isDrawed_Dict["fenge"] = true;

        AddFunction();
    }
    //定位
    locationBtn.onclick = function () {
        clearBrush();//清除
        if (!versionAlter()) {
            isDrawed_Dict["dingwei"] = !isDrawed_Dict["dingwei"];
        } else isDrawed_Dict["dingwei"] = true;
        AddFunction();
    }
    //纠正
    adjustBtn.onclick = function () {
        clearBrush();//清除
        if (!versionAlter()) {
            isDrawed_Dict["jiuzheng"] = !isDrawed_Dict["jiuzheng"];
        } else isDrawed_Dict["jiuzheng"] = true;
        AddFunction();
    }
    //格式
    formatBtn.onclick = function () {
        clearBrush();//清除
        if (!versionAlter()) {
            isDrawed_Dict["geshi"] = !isDrawed_Dict["geshi"];
        } else isDrawed_Dict["geshi"] = true;
        AddFunction();
    }
    //版本
    versionMessageBtn.onclick = function () {
        clearBrush();//清除
        if (!versionAlter()) {
            isDrawed_Dict["banben"] = !isDrawed_Dict["banben"];
        } else isDrawed_Dict["banben"] = true;
        AddFunction();
    }
    //布置路线
    lineBtn.onclick = function () {
        clearBrush();//清除
        if (!versionAlter()) {
            isDrawed_Dict["luxian"] = !isDrawed_Dict["luxian"];
        } else isDrawed_Dict["luxian"] = true;
        AddFunction();
    }
    //数据
    dataBtn.onclick = function () {
        let str = edtext.value;//文本框内容
        if (str == "") {
            // isDrawed_Dict=new Array;
            alert('请输入数据！');
            return;
        }
        // if(isDrawed_Dict["luxian"]) isDrawed_Dict["luxian"] = true;
        clearBrush();//清除

        if (isDrawed_Dict["yanmo"] || isDrawed_Dict["luxian"]) {
            isDrawed_Dict["yanmo"] = isDrawed_Dict["luxian"] = false;
            isDrawed_Dict["data"] = false;
        }

        isDrawed_Dict["data"] = !isDrawed_Dict["data"];

        if (versionAlter() || cacheDataArr[0] == undefined) {
            cacheDataArr = AddData();
            Draws(cacheDataArr);
            isDrawed_Dict = {
                "xunxiang": true, "fenge": true, "dingwei": true, "jiuzheng": true,
                "geshi": true, "banben": true, "luxian": false, "data": true
            };
            let data;
            //输出（模式指示符+字符计数指示符+数据）二进制数据
            if (GetVersion(MixingMode(str, 0).length) <= 9) data = MixingMode(str, 0);
            else if (GetVersion(MixingMode(str, 1).length) <= 26) data = MixingMode(str, 1);
            else data = MixingMode(str, 2);
            let version = GetVersion(data.length);//获取版本
            if (version < 2) isDrawed_Dict["jiuzheng"] = false;
            if (version < 7) isDrawed_Dict["banben"] = false;
        }
        AddFunction();
    }
    //掩膜
    coverBtn.onclick = function () {
        clearBrush();//清除
        if (!versionAlter()) {
            isDrawed_Dict["yanmo"] = !isDrawed_Dict["yanmo"];
        } else isDrawed_Dict["yanmo"] = true;
        let shieldIndicate = edtext.value;//文本框内容
        if ((select.options[select.selectedIndex].value).toString() != isAlterShield) {
            isDrawed_Dict["yanmo"] = true;
            isAlterShield = (select.options[select.selectedIndex].value).toString();
        }
        if (isDrawed_Dict["luxian"] && !isDrawed_Dict["yanmo"]) isDrawed_Dict["yanmo"] = true;
        isDrawed_Dict["luxian"] = false;
        AddFunction();
    }
    //生成
    resultBtn.onclick = function () {
        clearBrush();//清除
        if (!versionAlter()) {
            isDrawed_Dict["shengcheng"] = !isDrawed_Dict["shengcheng"];
        } else isDrawed_Dict["shengcheng"] = true;
        AddFunction();
    }
    //清除画布
    clear.onclick = function () {
        isDrawed_Dict = {
            "xunxiang": false, "fenge": false, "dingwei": false, "jiuzheng": false,
            "geshi": false, "banben": false, "luxian": false, "data": false, "yanmo": false, "shengcheng": false
        };
        clearBrush();
    }

    //清除
    function clearBrush() {
        Brush.fillStyle = '#ddd';
        Brush.fillRect(0, 0, Brush.window, Brush.Height);
    }
    function AddData() {
        let str = edtext.value;//文本框内容
        if (str == "") {
            alert('请输入数据！');
            return;
        }
        let data, version, vDataLength;
        //输出（模式指示符+字符计数指示符+数据）二进制数据
        if (GetVersion(MixingMode(str, 0).length) <= 9) data = MixingMode(str, 0);
        else if (GetVersion(MixingMode(str, 1).length) <= 26) data = MixingMode(str, 1);
        else data = MixingMode(str, 2);
        version = GetVersion(data.length);//获取版本
        vDataLength = GetVersionDataLength(version - 1);//获取版本最大数据容量
        data += GetFinish(vDataLength, data.length);//添加终止符
        data += GetFill(vDataLength, data.length);//添加填充码
        data = DataError(data, version);//最终数据字符串
        let resultArr = new Array();//存放最终数据的数组
        for (let i = 0; i < 17 + (version * 4); i++) {
            resultArr[i] = new Array(17 + (version * 4));
        }

        //将功能数据添加到数组内
        resultArr = LookFor(version, resultArr);//添加寻像图形和分隔符数据
        resultArr = Location(version, resultArr);//添加定位图形数据
        resultArr = Adjust(version, resultArr);//添加矫正图形数据
        resultArr = Format(version, (select.options[select.selectedIndex].value).toString(), resultArr);//添加格式信息图形数据
        resultArr = VersionMessage(version, resultArr);//添加版本信息图形数据
        //将数据添加到数组内
        for (let z = resultArr.length - 1, n = 0, direction = 0; z > 0; z -= 2, direction++) {
            if (z == 6) z--;
            if ((direction % 2) == 0) {
                for (let i = resultArr.length - 1; i >= 0; i--) {
                    for (let j = 0; j < 2; j++) {
                        if (resultArr[i][z - j] == undefined) {
                            resultArr[i][z - j] = data[n];
                            n++;
                        }
                    }
                }
            } else {
                for (let i = 0; i < resultArr.length; i++) {
                    for (let j = 0; j < 2; j++) {
                        if (resultArr[i][z - j] == undefined) {
                            resultArr[i][z - j] = data[n];
                            n++;
                        }
                    }
                }
            }
        }
        //防止出现数据位数不足导致出错
        for (let i = 0; i < resultArr.length; i++) {
            for (let j = 0; j < resultArr[0].length; j++) {
                if (resultArr[i][j] == undefined) resultArr[i][j] = 0;
            }
        }
        //分隔符
        for (let j = 0, i = 7; j < 8; j++) {
            resultArr[i][j] = 12;
            resultArr[j][i] = 12;
            resultArr[resultArr.length - 8][j] = 12;
            resultArr[resultArr.length - j - 1][i] = 12;
            resultArr[j][resultArr.length - 8] = 12;
            resultArr[i][resultArr.length - j - 1] = 12;
        }
        return resultArr;
    }

    //添加图形数据
    function AddFunction() {

        let str = edtext.value;//文本框内容
        if (str == "") {
            // isDrawed_Dict=new Array;
            alert('请输入数据！');
            return;
        }
        let data;
        //输出（模式指示符+字符计数指示符+数据）二进制数据
        if (GetVersion(MixingMode(str, 0).length) <= 9) data = MixingMode(str, 0);
        else if (GetVersion(MixingMode(str, 1).length) <= 26) data = MixingMode(str, 1);
        else data = MixingMode(str, 2);
        let version = GetVersion(data.length);//获取版本
        let resultArr = new Array();//存放最终数据的数组
        for (let i = 0; i < 17 + (version * 4); i++) {
            resultArr[i] = new Array(17 + (version * 4));
        }
        if (isDrawed_Dict["data"]) {
            //当数据发生改变但版本没变
            if (cacheDataArr.length != resultArr.length) cacheDataArr = AddData();
            for (let i = 0; i < cacheDataArr.length; i++) {
                for (let j = 0; j < cacheDataArr.length; j++) {
                    if (cacheDataArr[i][j] == 0 || cacheDataArr[i][j] == 1)
                        resultArr[i][j] = cacheDataArr[i][j];
                }
            }
        }

        let functionDict = {
            "xunxiang": xunxiang, "fenge": fenge, "dingwei": dingwei,
            "jiuzheng": jiuzheng, "geshi": geshi, "banben": banben, "yanmo": yanmo, "shengcheng": shengcheng
        };
        let keyArr = Object.keys(functionDict);

        for (let i = 0; i < keyArr.length; i++) {
            if (isDrawed_Dict[keyArr[i]]) functionDict[keyArr[i]]();
        }

        function xunxiang() {
            resultArr = LookFor(0, resultArr);
            for (let j = 0, i = 7; j < 8; j++) {
                resultArr[i][j] = undefined;
                resultArr[j][i] = undefined;
                resultArr[resultArr.length - 8][j] = undefined;
                resultArr[resultArr.length - j - 1][i] = undefined;
                resultArr[j][resultArr.length - 8] = undefined;
                resultArr[i][resultArr.length - j - 1] = undefined;
            }

        }
        function fenge() {
            for (let j = 0, i = 7; j < 8; j++) {
                resultArr[i][j] = 12;
                resultArr[j][i] = 12;
                resultArr[resultArr.length - 8][j] = 12;
                resultArr[resultArr.length - j - 1][i] = 12;
                resultArr[j][resultArr.length - 8] = 12;
                resultArr[i][resultArr.length - j - 1] = 12;
            }

        }
        function dingwei() {
            resultArr = Location(0, resultArr)

        }
        function jiuzheng() {
            if (version >= 2) {
                resultArr = Adjust(0, resultArr);
            }
        }
        function geshi() {
            //获取格式码
            let shieldIndicate = select.options[select.selectedIndex].value;
            resultArr = Format(version, shieldIndicate, resultArr);

        }
        function banben() {
            if (version < 7) {
                isDrawed_Dict["banben"] = true;
                return;
            }
            resultArr = VersionMessage(version, resultArr);

        }
        function luxian() {
            for (let i = 0; i < resultArr.length; i++) {
                for (let j = 0; j < resultArr.length; j++) {
                    if (resultArr[i][j] % 10 == 0 || resultArr[i][j] % 10 == 1) {
                        resultArr[i][j] = undefined;
                    }
                }
            }

            Line(resultArr);
        }
        function yanmo() {
            resultArr = Shield(resultArr, true);//掩摸
            for (let i = 0; i < resultArr.length; i++) {
                for (let j = 0; j < resultArr[0].length; j++) {
                    if (resultArr[i][j] == 0 || resultArr[i][j] == 1) {
                        resultArr[i][j] = (resultArr[i][j] == 0) ? 10 : 11;
                    }
                }
            }
        }
        function shengcheng() {
            for (let i = 0; i < resultArr.length; i++) {
                for (let j = 0; j < resultArr.length; j++) {
                    if (resultArr[i][j] != undefined)
                        resultArr[i][j] = resultArr[i][j] % 2 == 0 ? 8 : 9;
                }
            }
        }
        Draws(resultArr);
        //路线
        if (isDrawed_Dict["luxian"]) luxian();
    }

    //画图
    function Draws(resultArr) {

        //0,1画数据，2,3画定位，4,5画格式码，6,7画版本码，8,9画寻像和矫正，10,11画掩膜，12画分割
        let colorDict = { 0: "#CFFFFF", 1: "#00BBBB", 2: "#FFEAB8", 3: "#FFC800", 4: "#b0eeb0", 5: "#008000", 6: "#6C8BF7", 7: "#4111FF", 8: "#fff", 9: "#000", 10: "#FFBBC9", 11: "#FF6685", 12: "#EEAEEE" };
        let size = (Brush.window) / (resultArr.length);
        Brush.strokeStyle = '#000';
        Brush.lineWidth = 0.3;
        Brush.beginPath();
        for (let i = 0; i < resultArr.length; i++) {
            Brush.moveTo(i * size, 0);
            Brush.lineTo(i * size, resultArr.length * size);
            Brush.moveTo(0, i * size);
            Brush.lineTo(resultArr.length * size, i * size);
            for (let j = 0; j < resultArr[0].length; j++) {
                if (resultArr[i][j] != undefined) {
                    Brush.fillStyle = colorDict[resultArr[i][j]];
                    Brush.fillRect(j * size, i * size, size, size);
                }
            }
        }
        Brush.moveTo(resultArr.length * size, 0);
        Brush.lineTo(resultArr.length * size, resultArr.length * size);
        Brush.moveTo(0, resultArr.length * size);
        Brush.lineTo(resultArr.length * size, resultArr.length * size);
        Brush.stroke();
    }

    //判断版本是否发生改变
    function versionAlter() {
        //获取版本
        let str = edtext.value;//文本框内容
        if (str == "") {
            isDrawed_Dict = {
                "xunxiang": false, "fenge": false, "dingwei": false, "jiuzheng": false,
                "geshi": false, "banben": false, "luxian": false, "data": false
            };
            return;
        }
        let data;
        //输出（模式指示符+字符计数指示符+数据）二进制数据
        if (GetVersion(MixingMode(str, 0).length) <= 9) data = MixingMode(str, 0);
        else if (GetVersion(MixingMode(str, 1).length) <= 26) data = MixingMode(str, 1);
        else data = MixingMode(str, 2);
        let version = GetVersion(data.length);//获取版本
        if (version != recvV) {
            recvV = version;
            return true;
        } else return false;
    }

    /**数字模式
     * 
     * @param {输入的数据} str 
     * @param {版本区间级别} vClass
     */
    function DigitalMode(str, vClass) {
        //存储二进制数据，缓存需处理的数据
        let data, cacheData;
        //模式指示符 + 字符计数指示符
        data = "0001" + GetCharCount(str.length, "0001", vClass);
        //将输入的数据转成合适的二进制数据
        for (let i = 0; i < str.length; i += 3) {
            if (i + 3 <= str.length) {
                cacheData = parseInt(str.substring(i, i + 3)).toString(2);//将数据分组并转成二进制
                cacheData = "0000000000" + cacheData;//在数据前面添加足够的0
                data += cacheData.substring(cacheData.length - 10);//获取十位二进制数据
            } else {
                cacheData = parseInt(str.substring(i)).toString(2);//将数据分组并转成二进制
                cacheData = "0000000000" + cacheData;//在数据前面添加足够的0
                let num = str.length - i == 2 ? 7 : 4;//根据剩下的一位或者两位，决定数据位数
                data += cacheData.substring(cacheData.length - num);//获取7或4位数据
            }
        }
        return data;
    }

    /**数字字母模式
     * 
     * @param {输入的数据} str 
     * @param {版本区间级别} vClass
     */
    function LetterAndNumMode(str, vClass) {
        //存储二进制数据，缓存需处理的数据
        let data, cacheData;
        //模式指示符 + 字符计数指示符
        data = "0010" + GetCharCount(str.length, "0010", vClass);
        let charA = new Array(
            "0", "1", "2", "3", "4", "5", "6", "7", "8",
            "9", "A", "B", "C", "D", "E", "F", "G", "H",
            "I", "J", "K", "L", "M", "N", "O", "P", "Q",
            "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
            " ", "$", "%", "*", "+", "-", ".", "/", ":"
        );
        for (let i = 0; i < str.length; i += 2) {
            if (i == str.length - 1) {
                cacheData = charA.indexOf(str[i]).toString(2);
                cacheData = "000000" + cacheData;
                data += cacheData.substring(cacheData.length - 6);
            } else {
                cacheData = (charA.indexOf(str[i]) * 45) + charA.indexOf(str[i + 1]);
                cacheData = "00000000000" + (cacheData.toString(2));
                data += cacheData.substring(cacheData.length - 11);
            }
        }
        return data;
    }

    /**字节模式
     * 
     * @param {输入的数据} str 
     * @param {版本区间级别} vClass 
     */
    function ByteMode(str, vClass) {
        //存储二进制数据，缓存需处理的数据
        let data, cacheData;
        data = "0100" + GetCharCount(str.length, "0100", vClass);
        for (let i = 0; i < str.length; i++) {
            cacheData = str[i].charCodeAt();
            cacheData = "00000000" + cacheData.toString(2);
            data += cacheData.substring(cacheData.length - 8);
        }
        return data;
    }

    /**返回具体【模式指示符 + 字符计数指示符 + 数字位流】
     * 
     * @param {输入的字符串} str 
     * @param {版本区间级别（1~9 = 0 , 10~26 = 1 ，17~40 = 2）} vLevel 
     */
    function MixingMode(str, vClass) {
        let start = new Array();
        start[0] = [4, 4, 5];
        start[1] = [6, 7, 8];
        /*start[0]用于判断是否已数字模式开始
            字符串以数字开始后接字节模式专有字符，数字位数是否不小于[4,4,5]
        start[1]用于判断是否以字母数字模式开始
            字符串数字开始后接大写字母，数字位数是否小于[6,7,8]
            字符串以字母数字子字符开始后接字节模式专有字符，字母数字位数是否不小于[6,7,8]
        //注：应先判断是否以数字模式开始，再判断是否以字母数字模式开始*/

        //字节模式下判断是否转数字模式：后接连续数字的位数是否大于[6,8,9]
        let btCdg = new Array(6, 8, 9);
        //字节模式下判断是否转字母数字模式：后接连续字母数字子字符的位数是否大于[11,15,16]
        let btClt = new Array(11, 15, 16);
        //字母数字模式是否转数字模式：后接连续数字的位数是否大于[13,15,17]
        let leCdi = new Array(13, 15, 17);
        let data = "";//存储二进制数据
        let vC = vClass;//指示版本等级级别，1~9 = 0 , 10~26 = 1 ， 17~40 = 2

        //用于存储某一索引前有几位字符是数字
        let dgLength = new Array(str.length);
        //用于存储某一位索引前有几位字符属于字母数字
        let ltLength = new Array(str.length);
        //计算用于存储某一索引前有几位字符是数字或者字母数字
        for (let i = 0, n = 0; i < str.length; i++, n++) {
            let charType;
            dgLength[i] = 0, ltLength[i] = 0;
            for (let j = i; j < str.length; j++) {
                charType = str[j].charCodeAt();
                if (charType >= 48 && charType <= 57) {
                    dgLength[i]++;
                } else break;
            }
            for (let j = i; j < str.length; j++) {
                charType = str[j].charCodeAt();
                if ((charType >= 48 && charType <= 57) || ltBool(str[j])) {
                    ltLength[i]++;
                } else break;
            }
        }

        //如果字符串以数字开头
        if (str[0].charCodeAt() >= 48 && str[0].charCodeAt() <= 57) {
            //如果全部都为数字字符
            if (dgLength[0] >= str.length) {
                data = DigitalMode(str, vC);
                //data = str.length.toString() + " 个 1";
                return data;
                //如果连续的数字字符数 >= [6,7,8]
            } else if (dgLength[0] >= start[1][vC]) dgM(0);
            //字母模式字符比数字模式字符多，    //表示连续数字字符后一位是大写字母，否则表示后一位是字节模式专属字符
            //判断字母模式字符长度是否不小于 [6,7,8],或者字符串的全部字符都属于字母数字 //至少满足一个
            else if (ltLength[0] > dgLength[0] &&
                (ltLength[0] >= start[1][vC] || ltLength[0] >= str.length)) ltM(0);
            else btM(0);
            //大写字母或字母数字模式下特殊字符开头
        } else if (ltBool(str[0])) {
            if (ltLength[0] < start[1][vC] && ltLength[0] < str.length) {
                btM(0);
            } else ltM(0);
        } else btM(0);

        //数字模式
        function dgM(index) {//索引
            let count = dgLength[index];//获取指定索引往前有几位数字字符
            data += DigitalMode(str.substring(index, index + count), vC);//截取指定位数确定为数字模式
            //data += "(" + count.toString() + " 个 1)";
            let newindex = index + count;//确定新的索引值
            if (newindex >= str.length) return;//如果索引值大于等于字符串长度，表示完成
            //大写字母或字母数字模式下特殊字符开头
            if (ltBool(str[newindex])) {
                //如果数字字母模式字符个数大于[6,7,8]，或者剩下的字符以不足6位
                if (ltLength[newindex] >= start[1][vC] || (newindex + ltLength[newindex]) >= str.length) {
                    ltM(newindex);
                } else btM(newindex);
            } else btM(newindex);
        }
        //字母数字模式
        function ltM(index) {
            let count = ltLength[index];//获取指定索引往前有几位字母数字字符
            let num = 0;//存储要转字母数字模式的字符数量
            //用于计算有几个字符 应该用字母数字模式
            for (let i = index; i < count + index; i++) {
                //后面没有接[13,15,17]位的连续数字
                if (dgLength[i] < leCdi[vC]) {
                    num++;
                } else break;
            }
            data += LetterAndNumMode(str.substring(index, index + num), vC);
            //data += "(" + num.toString() + " 个 2)";
            //指示不需要转数字模式，或者字符串已经遍历完成
            if (num == count) {
                //如果没有结束（后面接字节模式字符），转字节模式
                if (index + count < str.length) btM(index + count);
                else return data;
            } else dgM(index + (count - (count - num)));
        }
        //字节模式
        function btM(index) {
            let count = 0;
            for (let i = index; i < str.length; i++) {
                if (dgLength[i] >= btCdg[vC]) {
                    //将count位的字符转为字节模式二进制数据
                    data += ByteMode(str.substring(index, index + count), vC);
                    //data += "(" + count.toString() + " 个 3)";
                    dgM(i);
                    break;
                } else if (ltLength[i] >= btClt[vC]) {
                    //将count位的字符转为字节模式二进制数据
                    data += ByteMode(str.substring(index, index + count), vC);
                    //data += "(" + count.toString() + " 个 3)";
                    ltM(i);
                    break;
                } else {
                    count++;
                }
                if (i == str.length - 1) {
                    //将剩下的所有位数转为字节模式二进制数据
                    data += ByteMode(str.substring(index, index + count), vC);
                    //data += "(" + count.toString() + " 个 3)";
                }
            }
        }
        function ltBool(c) {
            let charA = new Array(
                "A", "B", "C", "D", "E", "F", "G", "H",
                "I", "J", "K", "L", "M", "N", "O", "P", "Q",
                "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
                " ", "$", "%", "*", "+", "-", ".", "/", ":"
            );
            for (let i = 0; i < charA.length; i++) {
                if (c == charA[i]) return true;
            }
            return false;
        }
        return data;
    }

    /**获取字符计数指示符
     * 
     * @param {字符串数据长度} leng 
     * @param {模式码} mode 
     * @param {版本区间级别} vClass 
     */
    function GetCharCount(len, mode, vClass) {
        //最终返回的二进制数，模式数字
        let result = "", str, patternNum;

        //返回最终二进制数据的位数
        let countArr = new Array();
        countArr[0] = [10, 12, 14];//数字模式
        countArr[1] = [9, 11, 13];//字母数字模式
        countArr[2] = [8, 16, 16];//字节模式

        if (mode == '0001') patternNum = 0;//数字      
        else if (mode == '0010') patternNum = 1;//字母数字  
        else if (mode == '0100') patternNum = 2;//字节
        str = "0000000000000000" + len.toString(2);
        result = str.substring(str.length - countArr[patternNum][vClass]);
        return result;
    }

    /**根据数据长度返回版本
     * 
     * @param {二进制数据长度} datalength 
     */
    function GetVersion(datalength) {
        let vDataLength = new Array();//各版本数据最大容量
        vDataLength[0] = [152, 272, 440, 640, 864, 1088, 1248, 1552, 1856, 2192,
            2592, 2960, 3424, 3688, 4184, 4712, 5176, 5768, 6360, 6888, 7456,
            8048, 8752, 9392, 10208, 10960, 11744, 12248, 13048, 13880, 14744,
            15640, 16568, 17528, 18448, 19472, 20528, 21616, 22496, 23648];//L
        vDataLength[1] = [128, 224, 352, 512, 688, 864, 992, 1232, 1456, 1728,
            2032, 2320, 2672, 2920, 3320, 3624, 4056, 4504, 5016, 5352, 5712,
            6256, 6880, 7312, 8000, 8496, 9024, 9544, 10136, 10984, 11640,
            12328, 13048, 13800, 14496, 15312, 15936, 16816, 17728, 18672];//M
        vDataLength[2] = [104, 176, 272, 384, 496, 608, 704, 880, 1056, 1232,
            1440, 1648, 1952, 2088, 2360, 2600, 2936, 3176, 3560, 3880, 4096,
            4544, 4912, 5312, 5744, 6032, 6464, 6968, 7288, 7880, 8264,
            8920, 9368, 9848, 10288, 10832, 11408, 12016, 12656, 13328];//Q
        vDataLength[3] = [72, 128, 208, 288, 368, 480, 528, 688, 800, 976,
            1120, 1264, 1440, 1576, 1784, 2024, 2264, 2504, 2728, 3080,
            3248, 3536, 3712, 4112, 4304, 4768, 5024, 5288, 5608, 5960,
            6344, 6760, 7208, 7688, 7888, 8432, 8768, 9136, 9776, 10208];//H
        console.log(eC);
        for (let i = 0; i < 40; i++) {
            if (vDataLength[eC][i] >= datalength) return i + 1;
        }
        return 40;
    }

    /**返回版本最大数据位数]
     * 
     * @param {没加终止符和填充码之前的数据的长度} dataLength 
     */
    function GetVersionDataLength(version) {
        let vDataLength = new Array();//各版本数据最大容量
        vDataLength[0] = [152, 272, 440, 640, 864, 1088, 1248, 1552, 1856, 2192,
            2592, 2960, 3424, 3688, 4184, 4712, 5176, 5768, 6360, 6888, 7456,
            8048, 8752, 9392, 10208, 10960, 11744, 12248, 13048, 13880, 14744,
            15640, 16568, 17528, 18448, 19472, 20528, 21616, 22496, 23648];//L
        vDataLength[1] = [128, 224, 352, 512, 688, 864, 992, 1232, 1456, 1728,
            2032, 2320, 2672, 2920, 3320, 3624, 4056, 4504, 5016, 5352, 5712,
            6256, 6880, 7312, 8000, 8496, 9024, 9544, 10136, 10984, 11640,
            12328, 13048, 13800, 14496, 15312, 15936, 16816, 17728, 18672];//M
        vDataLength[2] = [104, 176, 272, 384, 496, 608, 704, 880, 1056, 1232,
            1440, 1648, 1952, 2088, 2360, 2600, 2936, 3176, 3560, 3880, 4096,
            4544, 4912, 5312, 5744, 6032, 6464, 6968, 7288, 7880, 8264,
            8920, 9368, 9848, 10288, 10832, 11408, 12016, 12656, 13328];//Q
        vDataLength[3] = [72, 128, 208, 288, 368, 480, 528, 688, 800, 976,
            1120, 1264, 1440, 1576, 1784, 2024, 2264, 2504, 2728, 3080,
            3248, 3536, 3712, 4112, 4304, 4768, 5024, 5288, 5608, 5960,
            6344, 6760, 7208, 7688, 7888, 8432, 8768, 9136, 9776, 10208];//H
        console.log(eC);
        return vDataLength[eC][version];
    }

    /**返回终止符和需要补足的"0
     * 
     * @param {最大数据位数} maxDatalength 
     * @param {数据位数} dataLength 
     */
    function GetFinish(maxDatalength, dataLength) {
        let end = "00000000";
        if (maxDatalength - dataLength <= 4) {
            if (maxDatalength == dataLength) return "";
            else return end.substring(0, (maxDatalength - dataLength));
        } else return "0000" + end.substring(0, (8 - ((dataLength + 4) % 8)));
    }

    /**返回填充码
     * 
     * @param {最大数据位数} maxDatalength 
     * @param {数据位数} dataLength 
     */
    function GetFill(maxDatalength, dataLength) {
        let num = maxDatalength - dataLength;
        let fill = "1110110000010001", result = "";
        for (let i = 0; i < num; i++) {
            result += (fill[i % 16]);
        }
        return result;
    }

    /**进行纠错
     * 
     * @param {纠错前的数据} str 
     * @param {版本} version 
     */
    function DataError(str, version) {

        //afasdsadsadsafdsgsgdfgf
        //码字总数
        let codeNum = new Array(26, 44, 70, 100, 134, 172, 196, 242, 292, 346, 404, 466, 532, 581, 655, 733, 815, 901, 991, 1085, 1156, 1258,
            1364, 1474, 1588, 1706, 1828, 1921, 2051, 2185, 2323, 2465, 2611, 2761, 2876, 3034, 3196, 3362, 3532, 3706);

        let eCN = new Array();//纠错码字 数量
        eCN[0] = [7, 10, 15, 20, 26, 36, 40, 48, 60, 72, 80, 96, 104, 120, 132, 144, 168, 180, 196, 224, 224, 252, 270,
            300, 312, 336, 360, 390, 420, 450, 480, 510, 540, 570, 570, 600, 630, 660, 720, 750];
        eCN[1] = [10, 16, 26, 36, 48, 64, 72, 88, 110, 130, 150, 176, 198, 216, 240, 280, 308, 338, 364, 416, 442, 476, 504,
            560, 588, 644, 700, 728, 784, 812, 868, 924, 980, 1036, 1064, 1120, 1204, 1260, 1316, 1372];
        eCN[2] = [13, 22, 36, 52, 72, 96, 108, 132, 160, 192, 224, 260, 288, 320, 360, 408, 448, 504, 546, 600, 644, 690, 750,
            810, 870, 952, 1020, 1050, 1140, 1200, 1290, 1350, 1440, 1530, 1590, 1680, 1770, 1860, 1950, 2040];
        eCN[3] = [17, 28, 44, 64, 88, 112, 130, 156, 192, 224, 264, 308, 352, 384, 432, 480, 532, 588, 650, 700, 750, 816, 900,
            960, 1050, 1110, 1200, 1260, 1350, 1440, 1530, 1620, 1710, 1800, 1890, 1980, 2100, 2220, 2310, 2430];
        console.log(eC);
        //验证进行纠错的数据码字数是否正确
        if (str.length / 8 != codeNum[version - 1] - eCN[eC][version - 1]) {
            alert("进行纠错的数据不合格！");
            return;
        }

        let ePNum = new Array();
        //纠错等级为L的各版本纠错块数：（数据码+纠错码）
        ePNum[0] = [[1, 0], [1, 0], [1, 0], [1, 0], [1, 0], [2, 0], [2, 0], [2, 0], [2, 0], [2, 2], [4, 0], [2, 2], [4, 0], [3, 1], [5, 1], [5, 1], [1, 5], [5, 1],
        [3, 4], [3, 5], [4, 4], [2, 7], [4, 5], [6, 4], [8, 4], [10, 2], [8, 4], [3, 10], [7, 7], [5, 10], [13, 3], [17, 0], [17, 1], [13, 6], [12, 7], [6, 14], [17, 4], [4, 18], [20, 4], [19, 6]];
        //纠错等级为M的各版本纠错块数：（数据码+纠错码）
        ePNum[1] = [[1, 0], [1, 0], [1, 0], [2, 0], [2, 0], [4, 0], [4, 0], [2, 2], [3, 2], [4, 1], [1, 4], [6, 2], [8, 1], [4, 5], [5, 5], [7, 3], [10, 1], [9, 4], [3, 11],
        [3, 13], [17, 0], [17, 0], [4, 14], [6, 14], [8, 13], [19, 4], [22, 3], [3, 23], [21, 7], [19, 10], [2, 29], [10, 23], [14, 21], [14, 23], [12, 26], [6, 34], [29, 14], [13, 32], [40, 7], [18, 31]];
        //纠错等级为Q的各版本纠错块数：（数据码+纠错码）
        ePNum[2] = [[1, 0], [1, 0], [2, 0], [2, 0], [2, 2], [4, 0], [2, 4], [4, 2], [4, 4], [6, 2], [4, 4], [4, 6], [8, 4], [11, 5], [5, 7], [15, 2], [1, 15], [17, 1], [17, 4],
        [15, 5], [17, 6], [7, 16], [11, 14], [11, 16], [7, 22], [28, 6], [8, 26], [4, 31], [1, 37], [15, 25], [42, 1], [10, 35], [29, 19], [44, 7], [39, 14], [46, 10], [49, 10], [48, 14], [43, 22], [34, 34]];
        //纠错等级为L的各版本纠错块数：（数据码+纠错码）
        ePNum[3] = [[1, 0], [1, 0], [2, 0], [4, 0], [2, 2], [4, 0], [4, 1], [4, 2], [4, 4], [6, 2], [3, 8], [7, 4], [12, 4], [11, 5], [11, 7], [3, 13], [2, 17], [2, 19], [9, 16],
        [15, 10], [19, 6], [34, 0], [16, 14], [30, 2], [22, 13], [33, 4], [12, 28], [11, 31], [19, 26], [23, 25], [23, 28], [19, 35], [11, 46], [59, 1], [22, 41], [2, 64], [24, 46], [42, 32], [10, 67], [20, 61]];
        console.log(eC);
        //存放数据+纠错块的块数
        let pieceNum = ePNum[eC][version - 1];
        //纠错码字 数
        let eCodenum = eCN[eC][version - 1];
        //第一个数据码字数 //（当 pieceNum[1] 不等于0时，表示存在第二个数据码字数 = 第一个数据码字数+1）
        let dataCodeNum = (codeNum[version - 1] - eCodenum - pieceNum[1]) / (pieceNum[0] + pieceNum[1]);

        let dataArr = new Array();//存放最终数据码字的数组
        let errorArr = new Array();//存放最终纠错码字的数组

        //console.log(pieceNum[0]+pieceNum[1])
        //通过据+纠错块的块数确定两个二维数组需要存放的‘一维数组数量’
        for (let i = 0, n = 0; i < (pieceNum[0] + pieceNum[1]); i++) {
            dataArr[i] = new Array();
            errorArr[i] = new Array();
            if (i < pieceNum[0]) {
                for (let j = 0; j < dataCodeNum; j++, n++)
                    dataArr[i][j] = parseInt(str.substring(n * 8, n * 8 + 8), 2);
            } else {
                for (let j = 0; j < dataCodeNum + 1; j++, n++)
                    dataArr[i][j] = parseInt(str.substring(n * 8, n * 8 + 8), 2);
            }
        }
        let ecc = new ECC();
        ecc.structure();//声明ECC纠错类后先调用此方法，相当于java的构造方法

        for (let i = 0; i < errorArr.length; i++) {
            errorArr[i] = ecc.RsEncodeMsg(dataArr[i], eCodenum / (pieceNum[0] + pieceNum[1]));
            //console.log(errorArr[i].length);
            //删除纠错码字数组里的数据码字
            if (i < pieceNum[0]) errorArr[i].splice(0, dataCodeNum);
            else errorArr[i].splice(0, dataCodeNum + 1);

        }

        //缓存数据码字+纠错码字的一维数组
        let cacheArr = new Array();
        //将数据码字进行排序
        for (let i = 0, n = 0; i < dataArr[dataArr.length - 1].length; i++) {
            for (let j = 0; j < dataArr.length; j++) {
                if (dataArr[j][i] != undefined)
                    cacheArr.push(dataArr[j][i]);
            }
        }//将纠错码字进行排序

        for (let i = 0; i < errorArr[0].length; i++) {
            for (let j = 0; j < errorArr.length; j++) {
                cacheArr.push(errorArr[j][i]);
            }
        }
        //console.log(cacheArr)
        //console.log(cacheArr[.length]);
        let resultData = "", s;
        for (let i = 0; i < cacheArr.length; i++) {
            if (cacheArr[i] != undefined) {
                s = '00000000' + (cacheArr[i].toString(2));
                s = s.substring((s.length) - 8);
                resultData += s;
            }
        }
        return resultData;
    }

    /**画寻像图形和分隔图形，如果传入二维数组则返回添加了寻像图形数据的数组
     * 
     * @param {版本} version 
     * @param {二维数组} resultArr 
     */
    function LookFor(version, resultArr) {
        //let size = (Brush.window)/(17+(version*4));
        //画寻像符,由于声明两个画布对象是后声明的对象覆盖前面声明的对象，所以只能每次画都要改颜色
        /*{
            Brush.fillStyle = "#ffff00";
            Brush.fillRect(0,0,8*size,8*size);
            Brush.fillStyle = "#000000";
            Brush.fillRect(0,0,7*size,7*size);
            Brush.fillStyle = "#ffffff";
            Brush.fillRect(size,size,5*size,5*size);
            Brush.fillStyle = "#000000";
            Brush.fillRect(2*size,2*size,3*size,3*size);

            Brush.fillStyle = "#ffff00";
            Brush.fillRect(Brush.window,0,-8*size,8*size);
            Brush.fillStyle = "#000000";
            Brush.fillRect(Brush.window,0,-7*size,7*size);
            Brush.fillStyle = "#ffffff";
            Brush.fillRect(Brush.window-size,size,-5*size,5*size);
            Brush.fillStyle = "#000000";
            Brush.fillRect(Brush.window-(2*size),2*size,-3*size,3*size);

            Brush.fillStyle = "#ffff00";
            Brush.fillRect(0,Brush.window,8*size,-8*size);
            Brush.fillStyle = "#000000";
            Brush.fillRect(0,Brush.window,7*size,-7*size);
            Brush.fillStyle = "#ffffff";
            Brush.fillRect(size,Brush.window-size,5*size,-5*size);
            Brush.fillStyle = "#000000";
            Brush.fillRect(2*size,Brush.window-(2*size),3*size,-3*size);
        }*/
        //将数组添加寻像图形的数据，并返回
        if (resultArr != undefined) {
            let cacheArr = new Array(9, 9, 9, 9, 9, 9, 9, 8, 9, 8, 8, 8, 8, 8, 9, 8, 9, 8, 9, 9, 9, 8, 9, 8,
                9, 8, 9, 9, 9, 8, 9, 8, 9, 8, 9, 9, 9, 8, 9, 8, 9, 8, 8, 8, 8, 8, 9, 8, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8);

            for (let i = 0, n = 0; i < 8; i++) {
                for (let j = 0; j < 8; j++, n++) {
                    resultArr[i][j] = cacheArr[n];
                    resultArr[i][(resultArr.length - 1) - j] = cacheArr[n];
                    resultArr[(resultArr.length - 1) - i][j] = cacheArr[n];

                }
            }
            return resultArr;
        }

    }

    /**画定位图形，如果传入二维数组则返回添加了定位图形数据的数组
     * 
     * @param {版本} version 
     * @param {二维数组} resultArr 
     */
    function Location(version, resultArr) {
        //添加数据
        if (resultArr != undefined) {
            for (let i = 0; i < (resultArr.length - 16); i++) {
                resultArr[6][8 + i] = i % 2 == 0 ? 3 : 2;
            }
            for (let i = 0; i < (resultArr.length - 16); i++) {
                resultArr[8 + i][6] = i % 2 == 0 ? 3 : 2;
            }
            return resultArr;
        }
    }

    /**画矫正图形，如果传入二维数组则返回添加了矫正图形数据的数组
     * 
     * @param {版本} version 
     * @param {二维数组} resultArr 
     */
    function Adjust(version, resultArr) {
        version = ((resultArr.length - 21) / 4) + 1
        if (version < 2) return resultArr;
        let size = (Brush.window) / (17 + (version * 4));
        let abjustData = new Array(new Array(), new Array(),
            new Array(), new Array(), new Array(), new Array());
        abjustData[0] = [18, 22, 26, 30, 34, 22, 24, 26, 28, 30, 32, 34, 26, 26, 26, 30, 30,
            30, 34, 28, 26, 30, 28, 32, 30, 34, 26, 30, 26, 30, 34, 30, 34, 30, 24, 28, 32, 26, 30];
        abjustData[1] = [38, 42, 46, 50, 54, 58, 62, 46, 48, 50, 54, 56, 58, 62,
            50, 50, 54, 54, 58, 58, 62, 50, 54, 52, 56, 60, 58, 62, 54, 50, 54, 58, 54, 58];
        abjustData[2] = [66, 70, 74, 78, 82, 86, 90, 72, 74, 78, 80, 84, 86, 90, 74, 78, 78, 82, 86, 86, 90, 78, 76, 80, 84, 82, 86];
        abjustData[3] = [94, 98, 102, 106, 110, 114, 118, 98, 102, 104, 108, 112, 114, 118, 102, 102, 106, 110, 110, 114];
        abjustData[4] = [122, 126, 130, 134, 138, 142, 146, 126, 128, 132, 136, 138, 142];
        abjustData[5] = [150, 154, 158, 162, 166, 170];

        let dataArr = new Array();
        dataArr[0] = 6;
        if (version >= 2) dataArr[1] = abjustData[0][version - 2];
        for (let i = 1; i <= 5; i++) {
            if (version >= (i * 7)) dataArr[i + 1] = abjustData[i][version - (i * 7)]
            else break;
        }

        //let cacheArr = [3,3,3,3,3,3,2,2,2,3,3,2,3,2,3,3,2,2,2,3,3,3,3,3,3];
        //添加数据
        if (resultArr != undefined) {
            for (let i = 0; i < dataArr.length; i++) {
                for (let j = 0; j < dataArr.length; j++) {
                    if ((i == 0 && j == 0) || (i == 0 && j == dataArr.length - 1) || (i == dataArr.length - 1 && j == 0)) {
                        continue;
                    } else {
                        for (let n = 0; n < 5; n++) {
                            for (let m = 0; m < 5; m++)
                                resultArr[(dataArr[i] - 2) + n][(dataArr[j] - 2) + m] = 9;
                        }
                        for (let n = 0; n < 3; n++) {
                            for (let m = 0; m < 3; m++)
                                resultArr[(dataArr[i] - 1) + n][(dataArr[j] - 1) + m] = 8;
                        }
                        resultArr[dataArr[i]][dataArr[j]] = 9;
                    }
                }
            }
            return resultArr;
        }
    }

    /**画格式信息图形，如果传入二维数组则返回添加了格式信息图形数据的数组
     * 
     * @param {*} maskCode 掩摸图形码
     * @param {*} resultArr 二维数组
     */
    function Format(version, maskCode, resultArr) {

        let ecc = new ECC();
        ecc.structure();
        let formatData, cacheArr = new Array();

        for (let i = 0; i < resultArr.length; i++) {
            cacheArr[i] = new Array();
            for (let j = 0; j < resultArr[0].length; j++) {
                cacheArr[i][j] = resultArr[i][j];
            }
        }
        console.log("log1", eC, cacheArr);

        //给-errorCode-赋值纠错等级信息
        switch (eC) {
            case 0:
                formatData = parseInt('01' + maskCode, 2);
                break;
            case 1:
                formatData = parseInt('00' + maskCode, 2);
                break;
            case 2:
                formatData = parseInt('11' + maskCode, 2);
                break;
            default:
                formatData = parseInt('10' + maskCode, 2);
        }
        console.log("log2", formatData, maskCode);
        //console.log(maskCode);
        formatData = ecc.BCH_15_5_Encode(formatData) ^ 0x5412;
        formatData = '00000000000' + formatData.toString(2);
        formatData = formatData.substring(formatData.length - 15);
        console.log("log3", cacheArr, formatData);

        if (cacheArr != undefined) {
            for (let i = 0, n = 0, z = 0; i < 17 + (version * 4); i++) {
                if ((i <= 7 || i >= 17 + (version * 4) - 8) && i != 6) {
                    cacheArr[8][i] = (formatData[n] == 0) ? 4 : 5;
                    n++;
                }
                if ((i <= 8 || i >= 17 + (version * 4) - 7) && i != 6) {
                    cacheArr[i][8] = (formatData[(formatData.length - 1) - z] == 0) ? 4 : 5;
                    z++
                }
            }
            cacheArr[cacheArr.length - 8][8] = 5;
            console.log("log4", cacheArr);
            return cacheArr;
        }
    }

    /**画版本信息信息图形，如果传入二维数组则返回添加了版本信息图形数据的数组
     * 
     * @param {*} version 版本
     * @param {*} resultArr 二维数组
     */
    function VersionMessage(version, resultArr) {
        if (version < 7) return resultArr;
        let ecc = new ECC();
        ecc.structure();
        let versionCode = '000000' + ecc.BCH_18_6_Encode(version).toString(2);
        versionCode = versionCode.substring(versionCode.length - 18);
        if (resultArr != undefined) {
            for (let i = 5, n = 0; i >= 0; i--) {
                for (let j = (version * 4) + 16 - 8; j >= (version * 4) + 16 - 10; j--) {
                    resultArr[j][i] = versionCode[n] == '0' ? 6 : 7;
                    resultArr[i][j] = versionCode[n] == '0' ? 6 : 7;
                    n++;
                }
            }
            return resultArr;
        }
    }

    /**走位线路
     * 
     * @param {*} resultArr 
     */
    function Line(resultArr) {
        let size = (Brush.window) / (resultArr.length);
        let coord = new Array(new Array, new Array);
        for (let n = resultArr.length - 1, z = 0; n >= 0; n -= 2, z++) {
            if (isDrawed_Dict["xunxiang"] && isDrawed_Dict["fenge"] && isDrawed_Dict["dingwei"] && resultArr[8][n] == 3) n--;
            if (z % 2 == 0) {
                for (let i = resultArr.length - 1; i >= 0; i--) {
                    for (let j = 0; j < 2; j++) {
                        if (n - j < 0) break;
                        if (resultArr[i][n - j] == undefined) {
                            //背景
                            Brush.fillStyle = '#CAE1FF';
                            Brush.fillRect(i * size, (n - j) * size, size, size);
                            coord[0].push(i * size + (size / 2));//Y	
                            coord[1].push((n - j) * size + (size / 2));//X  
                        }
                    }
                }
            } else {
                for (let i = 0; i < resultArr.length; i++) {
                    for (let j = 0; j < 2; j++) {
                        if (resultArr[i][n - j] == undefined) {
                            Brush.fillStyle = '#CAE1FF';
                            Brush.fillRect(i * size, (n - j) * size, size, size);
                            coord[0].push(i * size + (size / 2));//Y
                            coord[1].push((n - j) * size + (size / 2));//X
                        }
                    }
                }
            }
        }
        Brush.strokeStyle = '#f00';
        Brush.lineWidth = 0.4;
        Brush.beginPath();
        for (let i = 0; i < coord[0].length - 1; i++) {
            Brush.moveTo(coord[1][i], coord[0][i]);
            Brush.lineTo(coord[1][i + 1], coord[0][i + 1]);
        }
        Brush.closePath();
        Brush.stroke();
        Brush.strokeStyle = '#000';
        for (let i = 0; i < resultArr.length; i++) {
            Brush.moveTo(i * size, 0);
            Brush.lineTo(i * size, resultArr.length * size);
            Brush.moveTo(0, i * size);
            Brush.lineTo(resultArr.length * size, i * size);
        }
        Brush.stroke();
    }

    /**返回最终数据
     * 
     * @param {*} dataArr 
     */
    function Shield(dataArr, shieldBool) {
        let resultArr = new Array(),
            cacheArr0 = new Array(),
            cacheArr1 = new Array(),
            cacheArr2 = new Array(),
            cacheArr3 = new Array(),
            cacheArr4 = new Array(),
            cacheArr5 = new Array(),
            cacheArr6 = new Array(),
            cacheArr7 = new Array();

        //重新输入格式信息数据
        cacheArr0 = Format((dataArr.length - 17) / 4, '000', dataArr);
        cacheArr1 = Format((dataArr.length - 17) / 4, '001', dataArr);
        cacheArr2 = Format((dataArr.length - 17) / 4, '010', dataArr);
        cacheArr3 = Format((dataArr.length - 17) / 4, '011', dataArr);
        cacheArr4 = Format((dataArr.length - 17) / 4, '100', dataArr);
        cacheArr5 = Format((dataArr.length - 17) / 4, '101', dataArr);
        cacheArr6 = Format((dataArr.length - 17) / 4, '110', dataArr);
        cacheArr7 = Format((dataArr.length - 17) / 4, '111', dataArr);

        //Brush.clearRect(0,0,Brush.window,Brush.Height);
        //计算八个掩摸后的数据图形

        for (let i = 0; i < dataArr.length; i++) {
            for (let j = 0; j < dataArr[0].length; j++) {
                if (dataArr[i][j] == 0 || dataArr[i][j] == 1) {
                    cacheArr0[i][j] ^= ((i + j) % 2 == 0) ? 1 : 0;//000	(i + j) mod 2 = 0
                    cacheArr1[i][j] ^= (i % 2 == 0) ? 1 : 0;//001	i mod 2 = 0
                    cacheArr2[i][j] ^= (j % 3 == 0) ? 1 : 0;//010	j mod 3 = 0
                    cacheArr3[i][j] ^= ((i + j) % 3 == 0) ? 1 : 0;//011	(i + j) mod 3 = 0
                    cacheArr4[i][j] ^= (((Math.trunc(i / 2) + Math.trunc(j / 3)) % 2) == 0) ? 1 : 0;//100	((i/2)+(j/3)) mod 2 = 0
                    cacheArr5[i][j] ^= (((i * j) % 2) + ((i * j) % 3) == 0) ? 1 : 0;//101	(i × j) mod 2 + (i × j) mod 3 = 0
                    cacheArr6[i][j] ^= ((((i * j) % 2) + ((i * j) % 3)) % 2 == 0) ? 1 : 0;//110	((i × j) mod 2 + (i × j) mod 3) mod 2 = 0
                    cacheArr7[i][j] ^= ((((i * j) % 3) + ((i + j) % 2)) % 2 == 0) ? 1 : 0;//111	((i × j) mod 3 + (i + j) mod 2) mod 2 = 0 

                } else if (dataArr[i][j] == undefined) {
                    cacheArr0[i][j] = ((i + j) % 2 == 0) ? 1 : 0;//000	(i + j) mod 2 = 0
                    cacheArr1[i][j] = (i % 2 == 0) ? 1 : 0;//001	i mod 2 = 0
                    cacheArr2[i][j] = (j % 3 == 0) ? 1 : 0;//010	j mod 3 = 0
                    cacheArr3[i][j] = ((i + j) % 3 == 0) ? 1 : 0;//011	(i + j) mod 3 = 0
                    cacheArr4[i][j] = (((Math.trunc(i / 2) + Math.trunc(j / 3)) % 2) == 0) ? 1 : 0;//100	((i/2)+(j/3)) mod 2 = 0
                    cacheArr5[i][j] = (((i * j) % 2) + ((i * j) % 3) == 0) ? 1 : 0;//101	(i × j) mod 2 + (i × j) mod 3 = 0
                    cacheArr6[i][j] = ((((i * j) % 2) + ((i * j) % 3)) % 2 == 0) ? 1 : 0;//110	((i × j) mod 2 + (i × j) mod 3) mod 2 = 0
                    cacheArr7[i][j] = ((((i * j) % 3) + ((i + j) % 2)) % 2 == 0) ? 1 : 0;//111	((i × j) mod 3 + (i + j) mod 2) mod 2 = 0 
                }
            }
        }
        if (shieldBool) {
            let shieldIndicate = parseInt(select.options[select.selectedIndex].value, 2);
            switch (shieldIndicate) {
                case 0:
                    return cacheArr0;
                case 1:
                    return cacheArr1;
                case 2:
                    return cacheArr2;
                case 3:
                    return cacheArr3;
                case 4:
                    return cacheArr4;
                case 5:
                    return cacheArr5;
                case 6:
                    return cacheArr6;
                default:
                    return cacheArr7;
            }
        }


        //return cacheArr0;
        let num = 0, max = 0;
        let count = new Array();
        count[0] = Scoring(cacheArr0);
        count[1] = Scoring(cacheArr1);
        count[2] = Scoring(cacheArr2);
        count[3] = Scoring(cacheArr3);
        count[4] = Scoring(cacheArr4);
        count[5] = Scoring(cacheArr5);
        count[6] = Scoring(cacheArr6);
        count[7] = Scoring(cacheArr7);
        for (let i = 0; i < count.length; i++) {
            if (count[i] > max) {
                max = count[i];
                num = i;
            }
        }
        if (num == 0) resultArr = cacheArr0;
        else if (num = 1) resultArr = cacheArr1;
        else if (num = 2) resultArr = cacheArr2;
        else if (num = 3) resultArr = cacheArr3;
        else if (num = 4) resultArr = cacheArr4;
        else if (num = 5) resultArr = cacheArr5;
        else if (num = 6) resultArr = cacheArr6;
        else if (num = 7) resultArr = cacheArr7;
        return resultArr;
    }

    /**计算各掩膜数据分数
     * 
     * @param {*} dataArr 
     */
    function Scoring(dataArr) {
        //一个用来计分，一个用来防止数组的指针发生错误
        let grade = 0, recvArr = new Array();
        //直接赋值是万恶之源
        for (let i = 0; i < dataArr.length; i++) {
            recvArr[i] = new Array();
            for (let j = 0; j < dataArr.length; j++) {
                recvArr[i][j] = dataArr[i][j] % 2 == 0 ? 0 : 1;
            }
        }

        //第一种计分   条件：模块数 = （5+i）     分数：3+i
        for (let i = 0; i < recvArr.length; i++) {
            for (let j = 0, num; j < recvArr.length; j += 1 + num) {
                num = 0;
                for (let n = 1; n < recvArr.length - j; n++) {
                    if (recvArr[i][j + n] == recvArr[i][j]) num++;
                    else break;
                }
                grade += num >= 5 ? 3 + num - 5 : 0;
            }
            for (let j = 0, num; j < recvArr.length; j += 1 + num) {
                num = 0;
                for (let n = 1; n < recvArr.length - j; n++) {
                    if (recvArr[j + n][i] == recvArr[j][i]) num++;
                    else break;
                }
                grade += num >= 5 ? 3 + num - 5 : 0;
            }
        }

        /*第三种计分 条件：行/列中出现——深-浅-深-深-深-浅-深-浅-浅-浅-浅，
                        或者——浅-浅-浅-浅-深-浅-深-深-深-浅-深，   分数：40*/
        {
            let arr1 = new Array(1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0),
                arr2 = new Array(0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1),
                arr = new Array(new Array(), new Array());
            for (let i = 0; i < recvArr.length; i++) {
                //检查每一行每一列
                for (let j = 0; j <= recvArr.length - 11; j++) {
                    for (let n = 0; n < 11; n++) {//将前面十一位数据存a中，用来判断是否为计分条件
                        //检查行
                        arr[0][n] = recvArr[i][j + n] % 2;//因为功能图形的数据是2、3，所以要mod上2
                        //检查列
                        arr[1][n] = recvArr[j + n][i] % 2;
                    }
                    if (JSON.stringify(arr[0]) == JSON.stringify(arr1) || JSON.stringify(arr[0]) == JSON.stringify(arr2)) {
                        grade += 40;
                    }
                    if (JSON.stringify(arr[1]) == JSON.stringify(arr1) || JSON.stringify(arr[1]) == JSON.stringify(arr2)) {
                        grade += 40;
                    }
                }

            }
        }

        /*第四种计分    条件：整个图形中深色模块的比率，50 ± (5*k)%到50 ± (5*(k+1))%
         * 分数：10*k                注：k 为符号深色模块所占比率离50%的差距，步长为5%
         */
        {
            //模块总数，深色模块
            let totalmodules = recvArr.length * recvArr.length, darkmodules = 0;
            for (let i = 0; i < recvArr.length; i++) {
                for (let j = 0; j < recvArr.length; j++) {
                    if (recvArr[i][j] % 2 == 1) darkmodules++;
                }
            }
            //dark的占比
            let recvD = new Array();
            recvD[0] = (darkmodules / totalmodules) * 100;
            recvD[1] = parseInt(recvD[0] - (recvD[0] % 5));
            recvD[2] = parseInt((recvD[0] - (recvD[0] % 5)) + 5);
            //确定最大和最小的K值
            recvD[1] = (Math.abs(recvD[1] - 50)) / 5;
            recvD[2] = (Math.abs(recvD[2] - 50)) / 5;
            grade += (10 * Math.min(recvD[1], recvD[2]));
        }

        //第二种计分   条件：块尺寸 = m*n    分数：3*（m-1）*（n-1）
        {
            for (let i = 0; i < recvArr.length; i++) {
                for (let j = 0; j < recvArr.length; j++) {
                    if (recvArr[i][j] == 2 || recvArr[i][j] == 3
                        || i == recvArr.length - 1 || j == recvArr.length - 1) continue;
                    let num = 0;//判断是否存在2x2模块
                    for (let n = 0; n < 2; n++) {
                        if (recvArr[i][j + n] == recvArr[i][j]) num++;
                        if (recvArr[i + 1][j + n] == recvArr[i][j]) num++;
                    }

                    if (num < 4) continue;
                    let length1 = 0, length2 = 0;
                    for (let n = i; n < recvArr.length; n++) {
                        //从上往下，如果下一个等于第一个的话length1++
                        if (recvArr[n][j] == recvArr[i][j]) length1++;
                        else break;
                    }
                    for (let n = j; n < recvArr.length; n++) {
                        //从左往右，如果下一个等于第一个的话length1++
                        if (recvArr[i][n] == recvArr[i][j]) length2++;
                        else break;
                    }
                    let coorArr = new Array(new Array(), new Array());
                    for (let y = 0; y < length1; y++) {
                        coorArr[0][y] = 0;
                        for (let x = 0; x < length2; x++) {
                            if (recvArr[i + y][j + x] == recvArr[i][j]) coorArr[0][y]++;
                        }
                    }
                    for (let y = 0; y < length2; y++) {
                        coorArr[1][y] = 0;
                        for (let x = 0; x < length1; x++) {
                            if (recvArr[i + x][j + y] == recvArr[i][j]) coorArr[1][y]++;
                        }
                    }
                    let k = new Array(0, 0, 0);
                    for (let n = 0; n < coorArr[0].length; n++) {
                        if ((coorArr[0][n] * coorArr[1][coorArr[0][n]]) > k[0]) {
                            k[0] = (coorArr[0][n] * coorArr[1][coorArr[0][n]]);
                            k[1] = coorArr[0][n];
                            k[2] = coorArr[1][coorArr[0][n]];
                        }
                    }
                    for (let n = 0; n < k[1]; n++) {
                        for (let m = 0; m < k[2]; m++) {
                            recvArr[n][m] = 3;
                        }
                    }
                    if (k[1] > 1 && k[2] > 1) {
                        grade += 3 * (k[1] - 1) * (k[2] - 1);
                    }
                }
            }
        }
        return grade;
    }
}
function ECC() {

    let generators = {
        7: [1, 127, 122, 154, 164, 11, 68, 117],
        10: [1, 216, 194, 159, 111, 199, 94, 95, 113, 157, 193],
        13: [1, 137, 73, 227, 17, 177, 17, 52, 13, 46, 43, 83, 132, 120],
        15: [1, 29, 196, 111, 163, 112, 74, 10, 105, 105, 139, 132, 151, 32, 134, 26],
        16: [1, 59, 13, 104, 189, 68, 209, 30, 8, 163, 65, 41, 229, 98, 50, 36, 59],
        17: [1, 119, 66, 83, 120, 119, 22, 197, 83, 249, 41, 143, 134, 85, 53, 125, 99, 79],
        18: [1, 239, 251, 183, 113, 149, 175, 199, 215, 240, 220, 73, 82, 173, 75, 32, 67, 217, 146],
        20: [1, 152, 185, 240, 5, 111, 99, 6, 220, 112, 150, 69, 36, 187, 22, 228, 198, 121, 121, 165, 174],
        22: [1, 89, 179, 131, 176, 182, 244, 19, 189, 69, 40, 28, 137, 29, 123, 67, 253, 86, 218, 230, 26, 145, 245],
        24: [1, 122, 118, 169, 70, 178, 237, 216, 102, 115, 150, 229, 73, 130, 72, 61, 43, 206, 1, 237, 247, 127, 217, 144, 117],
        26: [1, 246, 51, 183, 4, 136, 98, 199, 152, 77, 56, 206, 24, 145, 40, 209, 117, 233, 42, 135, 68, 70, 144, 146, 77, 43, 94],
        28: [1, 252, 9, 28, 13, 18, 251, 208, 150, 103, 174, 100, 41, 167, 12, 247, 56, 117, 119, 233, 127, 181, 100, 121, 147, 176, 74, 58, 197],
        30: [1, 212, 246, 77, 73, 195, 192, 75, 98, 5, 70, 103, 177, 22, 217, 138, 51, 181, 246, 72, 25, 18, 46, 228, 74, 216, 195, 11, 106, 130, 150],
        32: [1, 116, 64, 52, 174, 54, 126, 16, 194, 162, 33, 33, 157, 176, 197, 225, 12, 59, 55, 253, 228, 148, 47, 179, 185, 24, 138, 253, 20, 142, 55, 172, 88],
        34: [1, 206, 60, 154, 113, 6, 117, 208, 90, 26, 113, 31, 25, 177, 132, 99, 51, 105, 183, 122, 22, 43, 136, 93, 94, 62, 111, 196, 23, 126, 135, 67, 222, 23, 10],
        36: [1, 28, 196, 67, 76, 123, 192, 207, 251, 185, 73, 124, 1, 126, 73, 31, 27, 11, 104, 45, 161, 43, 74, 127, 89, 26, 219, 59, 137, 118, 200, 237, 216, 31, 243, 96, 59],
        40: [1, 210, 248, 240, 209, 173, 67, 133, 167, 133, 209, 131, 186, 99, 93, 235, 52, 40, 6, 220, 241, 72, 13, 215, 128, 255, 156, 49, 62, 254, 212, 35, 99, 51, 218, 101, 180, 247, 40, 156, 38],
        42: [1, 108, 136, 69, 244, 3, 45, 158, 245, 1, 8, 105, 176, 69, 65, 103, 107, 244, 29, 165, 52, 217, 41, 38, 92, 66, 78, 34, 9, 53, 34, 242, 14, 139, 142, 56, 197, 179, 191, 50, 237, 5, 217],
        44: [1, 174, 128, 111, 118, 188, 207, 47, 160, 252, 165, 225, 125, 65, 3, 101, 197, 58, 77, 19, 131, 2, 11, 238, 120, 84, 222, 18, 102, 199, 62, 153, 99, 20, 50, 155, 41, 221, 229, 74, 46, 31, 68, 202, 49],
        46: [1, 129, 113, 254, 129, 71, 18, 112, 124, 220, 134, 225, 32, 80, 31, 23, 238, 105, 76, 169, 195, 229, 178, 37, 2, 16, 217, 185, 88, 202, 13, 251, 29, 54, 233, 147, 241, 20, 3, 213, 18, 119, 112, 9, 90, 211, 38],
        48: [1, 61, 3, 200, 46, 178, 154, 185, 143, 216, 223, 53, 68, 44, 111, 171, 161, 159, 197, 124, 45, 69, 206, 169, 230, 98, 167, 104, 83, 226, 85, 59, 149, 163, 117, 131, 228, 132, 11, 65, 232, 113, 144, 107, 5, 99, 53, 78, 208],
        50: [1, 247, 51, 213, 209, 198, 58, 199, 159, 162, 134, 224, 25, 156, 8, 162, 206, 100, 176, 224, 36, 159, 135, 157, 230, 102, 162, 46, 230, 176, 239, 176, 15, 60, 181, 87, 157, 31, 190, 151, 47, 61, 62, 235, 255, 151, 215, 239, 247, 109, 167],
        52: [1, 248, 5, 177, 110, 5, 172, 216, 225, 130, 159, 177, 204, 151, 90, 149, 243, 170, 239, 234, 19, 210, 77, 74, 176, 224, 218, 142, 225, 174, 113, 210, 190, 151, 31, 17, 243, 235, 118, 234, 30, 177, 175, 53, 176, 28, 172, 34, 39, 22, 142, 248, 10],
        54: [1, 196, 6, 56, 127, 89, 69, 31, 117, 159, 190, 193, 5, 11, 149, 54, 36, 68, 105, 162, 43, 189, 145, 6, 226, 149, 130, 20, 233, 156, 142, 11, 255, 123, 240, 197, 3, 236, 119, 59, 208, 239, 253, 133, 56, 235, 29, 146, 210, 34, 192, 7, 30, 192, 228],
        56: [1, 52, 59, 104, 213, 198, 195, 129, 248, 4, 163, 27, 99, 37, 56, 112, 122, 64, 168, 142, 114, 169, 81, 215, 162, 205, 66, 204, 42, 98, 54, 219, 241, 174, 24, 116, 214, 22, 149, 34, 151, 73, 83, 217, 201, 99, 111, 12, 200, 131, 170, 57, 112, 166, 180, 111, 116],
        58: [1, 211, 248, 6, 131, 97, 12, 222, 104, 173, 98, 28, 55, 235, 160, 216, 176, 89, 168, 57, 139, 227, 21, 130, 27, 73, 54, 83, 214, 71, 42, 190, 145, 51, 201, 143, 96, 236, 44, 249, 64, 23, 43, 48, 77, 204, 218, 83, 233, 237, 48, 212, 161, 115, 42, 243, 51, 82, 197],
        60: [1, 104, 132, 6, 205, 58, 21, 125, 141, 72, 141, 86, 193, 178, 34, 86, 59, 24, 49, 204, 64, 17, 131, 4, 167, 7, 186, 124, 86, 34, 189, 230, 211, 74, 148, 11, 140, 230, 162, 118, 177, 232, 151, 96, 49, 107, 3, 50, 127, 190, 68, 174, 172, 94, 12, 162, 76, 225, 128, 39, 44],
        62: [1, 190, 112, 31, 67, 188, 9, 27, 199, 249, 113, 1, 236, 74, 201, 4, 61, 105, 118, 128, 26, 169, 120, 125, 199, 94, 30, 9, 225, 101, 5, 94, 206, 50, 152, 121, 102, 49, 156, 69, 237, 235, 232, 122, 164, 41, 197, 242, 106, 124, 64, 28, 17, 6, 207, 98, 43, 204, 239, 37, 110, 103, 52],
        64: [1, 193, 10, 255, 58, 128, 183, 115, 140, 153, 147, 91, 197, 219, 221, 220, 142, 28, 120, 21, 164, 147, 6, 204, 40, 230, 182, 14, 121, 48, 143, 77, 228, 81, 85, 43, 162, 16, 195, 163, 35, 149, 154, 35, 132, 100, 100, 51, 176, 11, 161, 134, 208, 132, 244, 176, 192, 221, 232, 171, 125, 155, 228, 242, 245],
        66: [1, 32, 199, 138, 150, 79, 79, 191, 10, 159, 237, 135, 239, 231, 152, 66, 131, 141, 179, 226, 246, 190, 158, 171, 153, 206, 226, 34, 212, 101, 249, 229, 141, 226, 128, 238, 57, 60, 206, 203, 106, 118, 84, 161, 127, 253, 71, 44, 102, 155, 60, 78, 247, 52, 5, 252, 211, 30, 154, 194, 52, 179, 3, 184, 182, 193, 26],
        68: [1, 131, 115, 9, 39, 18, 182, 60, 94, 223, 230, 157, 142, 119, 85, 107, 34, 174, 167, 109, 20, 185, 112, 145, 172, 224, 170, 182, 107, 38, 107, 71, 246, 230, 225, 144, 20, 14, 175, 226, 245, 20, 219, 212, 51, 158, 88, 63, 36, 199, 4, 80, 157, 211, 239, 255, 7, 119, 11, 235, 12, 34, 149, 204, 8, 32, 29, 99, 11]
    };
    var PRIM = 0x11d;
    var gfExp = new Array(512);
    var gfLog = new Array(256);

    /**
     * 声明ECC类时调用的方法，参考构造方法。不会写JS的构造方法 只能这样
     */
    this.structure = function () {
        let x = 1;
        for (let i = 0; i <= 255; i++) {
            gfExp[i] = x;
            gfLog[x] = i;
            x = this.Gf_MultNoLUT(x, 2);
        }

        for (let i = 255; i < 512; i++) {
            gfExp[i] = gfExp[i - 255];
        }
    }

    /**
     * 生成 BCH(15,5) 纠错码，并返回完整格式信息码
     * @param {*} data 数据码
     */
    this.BCH_15_5_Encode = function (data) {
        let g = 0x537;
        let fmt = data << 10;
        for (let i = 4; i >= 0; i--) {
            if ((fmt & (1 << (i + 10))) != 0) {
                fmt ^= g << i;
            }
        }
        return (data << 10) ^ fmt;
    }

    /**
     * 生成 BCH(18,6) 纠错码，并返回完整版本信息码
     * @param {*} data 数据码
     */
    this.BCH_18_6_Encode = function (data) {
        let g = 0x1F25;
        let fmt = data << 12;
        for (let i = 5; i >= 0; i--) {
            if ((fmt & (1 << (i + 12))) != 0) {
                fmt ^= g << i;
            }
        }
        return (data << 12) ^ fmt;
    }

    //伽罗华域乘法
    this.Gf_MultNoLUT = function (x, y) {
        let r = 0;
        while (y != 0) {
            if ((y & 1) != 0) {
                r ^= x;
            }
            y >>= 1;
            x <<= 1;
            if ((x & 256) != 0) {
                x ^= PRIM;
            }
        }
        return r;
    }

    //伽罗华域乘法
    this.GfMul = function (x, y) {
        if (x == 0 || y == 0) {
            return 0;
        }
        return gfExp[gfLog[x] + gfLog[y]];
    }

    //伽罗华域幂
    this.GfPow = function (x, power) {
        return gfExp[(gfLog[x] * power) % 255];
    }

    //多项式 乘法
    this.GfPolyMul = function (p, q) {
        let r = new Arra(p.length + q.length - 1);
        for (let j = 0; j < q.length; j++) {
            for (let i = 0; i < p.length; i++) {
                r[i + j] ^= this.GfMul(p[i], q[j]);
            }
        }
        return r;
    }

    /**
     * 获取纠错码字的生成多项式
     * @param {*} nsym 纠错码字数
     */
    this.RsGeneratorPoly = function (nsym) {
        let g = new Array("1");
        for (let i = 0; i < nsym; i++) {
            g = this.GfPolyMul(parseInt(g), new Array(1, this.GfPow(2, i)));
        }
        return g;
    }

    /**
     * 生成纠错码，并添加在数据码字之后
     * @param {*} msgIn 数据码字
     * @param {*} nsym 纠错码字数
     */
    this.RsEncodeMsg = function (msgIn, nsym) {
        if (msgIn.length + nsym > 255) {
            //throw new ArgumentException("数组长度超过 255！");
            return null;
        }
        let gen = generators[nsym];
        let msgOut = new Array(msgIn.length + gen.length - 1);
        for (let i = 0; i < msgIn.length; i++) {
            msgOut[i] = msgIn[i];
        }
        for (let i = 0; i < msgIn.length; i++) {
            let coef = msgOut[i];
            if (coef != 0) {
                for (let j = 1; j < gen.length; j++) {
                    msgOut[i + j] ^= this.GfMul(gen[j], coef);
                }
            }
        }
        for (let i = 0; i < msgIn.length; i++) {
            msgOut[i] = msgIn[i];
        }
        return msgOut;
    }
}